package com.smmisia.auth.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.lang.Assert;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.smmisia.auth.exception.AuthException;
import com.smmisia.common.entity.auth.SysUserRole;
import com.smmisia.common.entity.auth.User;
import com.smmisia.common.entity.auth.convertor.UserConvertor;
import com.smmisia.common.enums.RoleEnum;
import com.smmisia.common.enums.StatusEnum;
import com.smmisia.common.request.auth.LoginRequest;
import com.smmisia.common.request.auth.UserRequest;
import com.smmisia.common.request.auth.UserUpdateRequest;
import com.smmisia.auth.mapper.SysUserRoleMapper;
import com.smmisia.auth.mapper.UserMapper;
import com.smmisia.auth.page.UserPage;
import com.smmisia.common.request.auth.CodeRequest;
import com.smmisia.common.request.auth.RegisterRequest;
import com.smmisia.auth.service.UserService;
import com.smmisia.auth.utls.SlidingWindowRateLimiter;
import com.smmisia.common.Result.Result;
import com.smmisia.common.enums.ResultCodeEnum;
import com.smmisia.common.response.auth.CodeResponse;
import com.smmisia.common.response.auth.UserResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RBloomFilter;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static com.smmisia.auth.exception.AuthErrorCode.*;

/**
 * 用户服务实现类
 *
 * @author smmisia
 * @version 1.0
 * @date 2023/10/27
 */
@Service
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserMapper, User>
        implements UserService, InitializingBean {

    private final String LOGIN = "login:code:";

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private SysUserRoleMapper sysUserRoleMapper;

    @Autowired
    private RedissonClient redissonClient;

    @Autowired
    protected ApplicationContext applicationContext;

    private RBloomFilter<String> emailBloomFilter;

    @Autowired
    private SlidingWindowRateLimiter slidingWindowRateLimiter;


    /**
     * 获取验证码
     *
     * @param request
     * @return
     */
    @Override
    public Result<CodeResponse> code(CodeRequest request) {
        //滑动窗口限流
        Boolean access = slidingWindowRateLimiter.tryAcquire(request.getEmail(), 1, 60);
        if (!access) {
            throw new RuntimeException("请不要重复获取验证码");
        }
        String title = "极致之旅";
        Random random = new Random();
        int sixDigit = random.nextInt(900000) + 100000;
        String code = String.valueOf(sixDigit);
        String content = String.format("欢迎使用极致之旅，登录验证码为:%s，五分钟有效，请妥善保管", code);
        String codeKey = LOGIN+request.getEmail();
        redisTemplate.opsForValue().set(codeKey, code, 300L, TimeUnit.SECONDS);
        String token = UUID.randomUUID().toString();
        return Result.ok(CodeResponse.builder().code(code).build());
    }

    /**
     * 用户注册
     *
     * @param request
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<String> register(RegisterRequest request) {
        //检查布隆过滤器中是否存在
        if (emailExist(request.getEmail())) {
            throw new AuthException(USER_EXIST);
        }
        doRegister(request);
        addEmail(request.getEmail());
        return Result.ok("注册成功");
    }

    public boolean emailExist(String email) {
        if (this.emailBloomFilter != null && this.emailBloomFilter.contains(email)) {
            //存在则查询数据库，布隆过滤器存在误判
            LambdaQueryWrapper<User> userWrapper = Wrappers.lambdaQuery();
            userWrapper.eq(User::getEmail, email);

            return userMapper.selectOne(userWrapper) != null;
        }
        return false;
    }

    public boolean addEmail(String email) {
        return this.emailBloomFilter != null && this.emailBloomFilter.add(email);
    }

    public void doRegister(RegisterRequest request) {
        User user = User.create(request);
        Long uid = redisTemplate.opsForValue().increment("uid", 1);
        user.setUid(String.valueOf(uid));
        int result;
        boolean save = save(user);
        Assert.isTrue(save, () -> new AuthException(INSERT_FAILED));
        SysUserRole sysUserRole = SysUserRole
                .create(Long.valueOf(user.getId()), Long.valueOf(RoleEnum.USER.getCode()));
        result = sysUserRoleMapper.insert(sysUserRole);
        Assert.isTrue(result > 0, () -> new AuthException(INSERT_FAILED));
    }

    /**
     * 用户登录
     *
     * @param loginRequest
     * @return
     */
    @Override
    public Result<String> doLogin(LoginRequest loginRequest) {
        String loginKey = LOGIN+loginRequest.getEmail();
        String code = (String) redisTemplate.opsForValue().get(loginKey);
        LambdaQueryWrapper<User> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(User::getEmail, loginRequest.getEmail());
        User user = userMapper.selectOne(wrapper);
        if (StringUtils.isEmpty(code)) {
            return Result.fail(ResultCodeEnum.FAIL.getCode(), "请先获取验证码");
        }
        Assert.notNull(user, () -> new AuthException(USER_NOT_EXIST));
        if (code.equals(loginRequest.getCode())) {
            StpUtil.login(user.getId());
            redisTemplate.delete(loginKey);
            String token = StpUtil.getTokenInfo().getTokenValue();
            return Result.ok(token);
        }
        return Result.fail(ResultCodeEnum.FAIL.getCode(), "验证码错误");
    }

    /**
     * 获取当前用户信息
     *
     * @return
     */
    @Override
    public Result<UserResponse> info() {
        String loginId = (String) StpUtil.getLoginId();
        User user = userMapper.selectById(Integer.valueOf(loginId));
        Assert.notNull(user, () -> new AuthException(USER_NOT_EXIST));
        UserResponse userResponse = UserConvertor.INSTANCE.mapToVo(user);
        return Result.ok(userResponse);
    }

    /**
     * 分页查询用户信息
     *
     * @param pageNum
     * @param pageSize
     * @return
     */
    @Override
    public Result<List<UserResponse>> infoList(Integer pageNum, Integer pageSize) {
        IPage<User> user = new Page<User>(pageNum, pageSize);
        List<User> records = userMapper.selectPage(user, null).getRecords();
        List<UserResponse> userResponseList = UserConvertor.INSTANCE.mapToVoList(records);
        UserPage userPage = new UserPage();
        userPage.setList(userResponseList);
        userPage.setTotal(user.getTotal());
        userPage.setPageNum(user.getCurrent());
        userPage.setPageSize(user.getSize());
        userPage.setPages(user.getPages());
        return Result.ok(userPage);
    }

    /**
     * 禁用/启用用户
     *
     * @param id
     * @return
     */
    @Override
    public Result<String> status(Integer id) {
        User user = userMapper.selectById(id);
        int result;
        if (user.getStatus() == StatusEnum.NORMAL) {
            user.setStatus(StatusEnum.DISABLE);
            result = userMapper.updateById(user);
            Assert.isTrue(result > 0, () -> new AuthException(UPDATE_FAILED));
            return Result.ok("禁用成功");
        } else {
            user.setStatus(StatusEnum.NORMAL);
        }
        result = userMapper.updateById(user);
        Assert.isTrue(result > 0, () -> new AuthException(UPDATE_FAILED));
        return Result.ok("启用成功");
    }

    /**
     * 更新用户信息
     *
     * @param userRequest
     * @return
     */

    @Override
    public Result<String> updateUserInfo(UserRequest userRequest) {
        User user = UserConvertor.INSTANCE.mapToEntity(userRequest);
        int result = userMapper.updateById(user);
        Assert.isTrue(result > 0, () -> new AuthException(UPDATE_FAILED));
        return Result.ok("修改成功");
    }

    /**
     * 删除用户信息
     *
     * @param id
     * @return
     */
    @Override
    public Result<String> deleteUserInfo(Integer id) {
        int result = userMapper.deleteById(id);
        Assert.isTrue(result > 0, () -> new AuthException(DELETE_FAILED));
        return Result.ok("删除成功");
    }

    /**
     * 搜索用户信息
     *
     * @param
     * @return
     */
    @Override
    public Result<String> search(String email) {
        User user = userMapper.selectOne(Wrappers.lambdaQuery(User.class).eq(User::getEmail, email));
        Assert.notNull(user, () -> new AuthException(USER_NOT_EXIST));
        return Result.ok(user.getId());
    }

    /**
     * 修改用户信息
     *
     * @param request
     * @return
     */
    @Override
    public Result<String> updateUserInfos(UserUpdateRequest request) {
        User user = UserConvertor.INSTANCE.mapToEntityByUserUpdateRequest(request);
        Integer loginId = StpUtil.getLoginIdAsInt();
        user.setId(loginId);
        int result = userMapper.updateById(user);
        Assert.isTrue(result > 0, () -> new AuthException(UPDATE_FAILED));
        user = userMapper.selectById(loginId);
        return Result.ok("修改成功");
    }

    @Override
    public User getUserById(Integer id) {
        User user = userMapper.selectById(id);
        Assert.notNull(user, () -> new AuthException(USER_NOT_EXIST));
        return user;
    }

    @Override
    public Result<String> jx(String targetUrl) throws IOException {
        String videoUrl = "";

        // 提取真实URL的正则表达式
        String urlRegex = "https://v\\.douyin\\.com/[a-zA-Z0-9]+/";
        Pattern urlPattern = Pattern.compile(urlRegex);
        Matcher urlMatcher = urlPattern.matcher(targetUrl);

        if (!urlMatcher.find()) {
            throw new RuntimeException("无效的抖音视频链接");
        }

        String extractedUrl = urlMatcher.group(0);

        // 创建URL连接
        URL url = new URL(extractedUrl);
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
        connection.setInstanceFollowRedirects(false);
        connection.setRequestProperty("User-Agent", "Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X)");

        int responseCode = connection.getResponseCode();
        String redirectUrl = connection.getHeaderField("Location");

        // 其余代码保持不变
        String regex = "/video/(\\d+)";
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(redirectUrl);
        String videoId = "";

        // If a match is found, extract the video ID
        if (matcher.find()) {
            videoId = matcher.group(1);
        }
        try {
            // 创建URL连接
            String urlString = "https://www.iesdouyin.com/share/video/+" + videoId + "/";

            URL newUrl = new URL(urlString);
            HttpURLConnection newConnection = (HttpURLConnection) newUrl.openConnection();
            // 设置请求头
            String userAgent = "Mozilla/5.0 (Linux; Android 8.0.0; SM-G955U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Mobile Safari/537.36";
            String referer = "https://www.douyin.com/?is_from_mobile_home=1&recommend=1";


            // 设置请求头
            newConnection.setRequestProperty("User-Agent", userAgent);
            newConnection.setRequestProperty("Referer", referer);

            // 读取响应内容
            StringBuilder response = new StringBuilder();
            try (BufferedReader reader = new BufferedReader(new InputStreamReader(newConnection.getInputStream()))) {
                String line;
                while ((line = reader.readLine()) != null) {
                    response.append(line);
                }
            }

            // 使用正则表达式提取JSON数据
            Pattern patterns = Pattern.compile("_ROUTER_DATA\\s*=\\s*(\\{.*?\\});");
            Matcher matchers = patterns.matcher(response.toString());

            if (matchers.find()) {
                String jsonData = matchers.group(1);
                Gson gson = new Gson();
                JsonObject jsonObject = gson.fromJson(jsonData, JsonObject.class);

                // 解析JSON数据
                JsonObject itemList = jsonObject
                        .getAsJsonObject("loaderData")
                        .getAsJsonObject("video_(id)/page")
                        .getAsJsonObject("videoInfoRes")
                        .getAsJsonArray("item_list")
                        .get(0)
                        .getAsJsonObject();

                // 提取信息
                String nickname = itemList.getAsJsonObject("author").get("nickname").getAsString();
                String title = itemList.get("desc").getAsString();
                String awemeId = itemList.get("aweme_id").getAsString();
                String videoUri = itemList.getAsJsonObject("video")
                        .getAsJsonObject("play_addr")
                        .get("uri").getAsString();

                // 构建视频URL
                videoUrl = videoUri.contains("mp3") ? videoUri :
                        "https://www.douyin.com/aweme/v1/play/?video_id=" + videoUri;

                String coverUrl = itemList.getAsJsonObject("video")
                        .getAsJsonObject("cover")
                        .getAsJsonArray("url_list")
                        .get(1).getAsString();

                // 输出结果
                System.out.println("标题: " + title);
                System.out.println("视频ID: " + awemeId);
                System.out.println("视频链接: " + videoUrl);
                System.out.println("封面图片: " + coverUrl);

                // 处理图片列表（如果存在）
                if (itemList.has("images")) {
                    JsonArray images = itemList.getAsJsonArray("images");
                    for (int i = 0; i < images.size(); i++) {
                        String imageUrl = images.get(i)
                                .getAsJsonObject()
                                .getAsJsonArray("url_list")
                                .get(0).getAsString();
                        System.out.println("图片" + (i + 1) + ": " + imageUrl);
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();

        }
        return Result.ok(videoUrl);
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        this.emailBloomFilter = redissonClient.getBloomFilter("email");
        if (emailBloomFilter != null && !emailBloomFilter.isExists()) {
            emailBloomFilter.tryInit(1000000L, 0.01);
        }
    }



}




